﻿using UnityEngine;
using System.Text;
using System.IO;
using System;

public class ByteArray
{
    // 数据类型
    public enum EDataType
    {
        TYPE_INT = 1,			// 数值类型
        TYPE_UINT,				// 数值类型
		TYPE_INT64,				// 数值类型
        TYPE_DOUBLE,			// 数值类型
		TYPE_FLOAT,				// 数值类型
		TYPE_USHORT,
		TYPE_SHORT,
		TYPE_UCHAR,
		TYPE_CHAR,
        TYPE_BOOLEAN,			// 布尔型
        TYPE_STRING,			// 字符串型
        TYPE_TABLE,				// 表类型
        TYPE_USERDATA,			// 用户数据
    };
    // 写入游标
    public uint mPos;
    // 读取游标
    public uint mTransPos;
    // 读取标记
    public uint mRecordPos;
    // 缓冲物理大小
    uint mSize;
    //	uint MAXSPARE = 65530;
    static MemoryStream sTempStream = new MemoryStream(65535);
    public byte[] mBytes = null;
    public ByteArray(uint vSize = 128)
    {
        mRecordPos = 0;
        mTransPos = 0;
        mPos = 0;
        mSize = vSize;
        mBytes = new byte[mSize];
    }
    public ByteArray(byte[] buf)
    {
        mRecordPos = 0;
        mTransPos = 0;
        mPos = (uint)buf.Length;
        mSize = (uint)buf.Length;
        mBytes = buf;
    }
	public void Create(byte[] buf)
	{
		mRecordPos = 0;
		mTransPos = 0;
		mPos = (uint)buf.Length;
		mSize = (uint)buf.Length;
		mBytes = buf;
	}

    public void TransBegin()
	{
		mRecordPos = mTransPos;
    }
    public void Rollback()
    {
        mTransPos = mRecordPos;
    }

    public void Commit()
    {
        Erase(0, mTransPos);
        mTransPos = 0;
    }

    public byte[] GetBytes()
    {
        return mBytes;
    }
    public uint GetSize()
    {
        return mSize;
    }

    public uint GetLength()
    {
        return mPos;
    }
    public bool IsEnd()
    {
        return mTransPos == mPos;
    }

	public void PushValue(byte vByteValue)
	{
		if (mPos + sizeof(byte) > mSize)
		{
			mSize = mSize + mSize;
			if ( mSize > 65535 )
                Debug.Log( "内存分配过大 - " + mSize );
				
			System.Array.Resize<byte>(ref mBytes, (int)mSize);
		}

		mBytes[ (int) mPos ] = vByteValue;
		mPos = mPos + sizeof(byte);
	}
	public void PushValue(sbyte vSByteValue)
	{
		if (mPos + sizeof(sbyte) > mSize)
		{
			mSize = mSize + mSize;
			if ( mSize > 65535 )
                Debug.Log( "内存分配过大 - " + mSize );

			System.Array.Resize<byte>(ref mBytes, (int)mSize);
		}
			
		System.BitConverter.GetBytes(vSByteValue).CopyTo(mBytes, (int)mPos);
		mPos = mPos + sizeof(sbyte);
	}		
	public void PushValue(int vIntValue)
    {
        if (mPos + sizeof(int) > mSize)
        {
            mSize = mSize + mSize;
			if ( mSize > 65535 )
                Debug.Log( "内存分配过大 - " + mSize );
                
			System.Array.Resize<byte>(ref mBytes, (int)mSize);
        }

        System.BitConverter.GetBytes(vIntValue).CopyTo(mBytes, (int)mPos);
        mPos = mPos + sizeof(int);
    }
    public void PushValue(uint vUIntValue)
    {
        if (mPos + sizeof(uint) > mSize)
        {
            mSize = mSize + mSize;
			if ( mSize > 65535 )
                Debug.Log( "内存分配过大 - " + mSize );

			System.Array.Resize<byte>(ref mBytes, (int)mSize);
        }

        System.BitConverter.GetBytes(vUIntValue).CopyTo(mBytes, (int)mPos);
        mPos = mPos + sizeof(uint);
    }
    public void PushValue(short vShortValue)
    {
        if (mPos + sizeof(short) > mSize)
        {
            mSize = mSize + mSize;
			if ( mSize > 65535 )
                Debug.Log( "内存分配过大 - " + mSize );

			System.Array.Resize<byte>(ref mBytes, (int)mSize);
        }

        System.BitConverter.GetBytes(vShortValue).CopyTo(mBytes, (int)mPos);
        mPos = mPos + sizeof(short);
    }
    public void PushValue(ushort value)
    {
        if (mPos + sizeof(ushort) > mSize)
        {
            mSize = mSize + mSize;
			if ( mSize > 65535 )
                Debug.Log( "内存分配过大 - " + mSize );

			System.Array.Resize<byte>(ref mBytes, (int)mSize);
        }

		System.BitConverter.GetBytes(value).CopyTo(mBytes, (int)mPos);
        mPos = mPos + sizeof(ushort);
    }
    public void PushValue(float vFloatValue)
    {
        if (mPos + sizeof(float) > mSize)
        {
            mSize = mSize + mSize;
			if ( mSize > 65535 )
                Debug.Log( "内存分配过大 - " + mSize );

			System.Array.Resize<byte>(ref mBytes, (int)mSize);
        }

        System.BitConverter.GetBytes(vFloatValue).CopyTo(mBytes, (int)mPos);
        mPos = mPos + sizeof(float);
    }
    public void PushValue(double vDoubleValue)
    {
        if (mPos + sizeof(double) > mSize)
        {
            mSize = mSize + mSize;
			if ( mSize > 65535 )
                Debug.Log( "内存分配过大 - " + mSize );

			System.Array.Resize<byte>(ref mBytes, (int)mSize);
        }

        System.BitConverter.GetBytes(vDoubleValue).CopyTo(mBytes, (int)mPos);
        mPos = mPos + sizeof(double);
    }		
	public void PushValue(long vLongValue)
	{
		if (mPos + sizeof(long) > mSize)
		{
			mSize = mSize + mSize;
			if ( mSize > 65535 )
                Debug.Log( "内存分配过大 - " + mSize );

			System.Array.Resize<byte>(ref mBytes, (int)mSize);
		}
			
		System.BitConverter.GetBytes(vLongValue).CopyTo(mBytes, (int)mPos);
		mPos = mPos + sizeof(long);
	}
	public void PushValue(bool value)
	{
		if (mPos + sizeof(bool) > mSize)
		{
            mSize = mSize + mSize;
			if ( mSize > 65535 )
                Debug.Log( "内存分配过大 - " + mSize );

			System.Array.Resize<byte>(ref mBytes, (int)mSize);
        }

        System.BitConverter.GetBytes(value).CopyTo(mBytes, (int)mPos);
        mPos = mPos + sizeof(bool);
    }
    public void PushValue(string value)
    {
        byte[] valueBuffer = Encoding.UTF8.GetBytes(value);
        if (mPos + valueBuffer.Length + sizeof(ushort) > mSize)
        {
            mSize = Math.Max(mSize + (uint)valueBuffer.Length + sizeof(ushort), mSize + mSize);
			if ( mSize > 65535 )
                Debug.Log( "内存分配过大 - " + mSize );

			System.Array.Resize<byte>(ref mBytes, (int)mSize);
        }

        System.BitConverter.GetBytes((ushort)valueBuffer.Length).CopyTo(mBytes, (int)mPos);
        mPos = mPos + sizeof(ushort);

        valueBuffer.CopyTo(mBytes, (int)mPos);
        mPos = mPos + (uint)valueBuffer.Length;
    }
    public void PushValue(ByteArray octets)
    {
        if (mPos + octets.GetLength() + sizeof(uint) > mSize)
        {
            mSize = Math.Max(mSize + (uint)octets.GetLength() + sizeof(uint), mSize + mSize);
			if ( mSize > 65535 )
                Debug.Log( "内存分配过大 - " + mSize );

			System.Array.Resize<byte>(ref mBytes, (int)mSize);
        }

        System.BitConverter.GetBytes((uint)octets.GetLength()).CopyTo(mBytes, (int)mPos);
        mPos = mPos + sizeof(uint);

        //			MemoryStream tStream = new MemoryStream( octets.GetBytes( ), 0, (int) octets.GetLength( ) );
        sTempStream.Position = 0;
        sTempStream.Write(octets.GetBytes(), 0, (int)octets.GetLength());
        sTempStream.Position = 0;
        sTempStream.Read(mBytes, (int)mPos, (int)octets.GetLength());
        mPos = mPos + (uint)octets.GetLength();
    }
			
	public bool PopValue(ref byte vValue)
	{
		if (mTransPos + sizeof(byte) > GetLength())
			return false;
			
		vValue = mBytes[ (int)mTransPos ];
		mTransPos = mTransPos + sizeof(byte);
		return true;
	}
	public bool PopValue(ref sbyte vValue)
	{
		if (mTransPos + sizeof(sbyte) > GetLength())
			return false;
			
		vValue = (sbyte) mBytes[ (int)mTransPos ];
		mTransPos = mTransPos + sizeof(sbyte);
		return true;
	}
	public bool PopValue(ref int vValue)
    {
        if (mTransPos + sizeof(int) > GetLength())
            return false;

        vValue = System.BitConverter.ToInt32(mBytes, (int)mTransPos);
        mTransPos = mTransPos + sizeof(int);
        return true;
    }
    public bool PopValue(ref uint vValue)
    {
        if (mTransPos + sizeof(uint) > GetLength())
            return false;

        vValue = System.BitConverter.ToUInt32(mBytes, (int)mTransPos);
        mTransPos = mTransPos + sizeof(uint);
        return true;
    }
    public bool PopValue(ref short vValue)
    {
        if (mTransPos + sizeof(short) > GetLength())
            return false;

        vValue = System.BitConverter.ToInt16(mBytes, (int)mTransPos);
        mTransPos = mTransPos + sizeof(short);
        return true;
    }
    public bool PopValue(ref ushort vValue)
    {
        if (mTransPos + sizeof(ushort) > GetLength())
            return false;

        vValue = System.BitConverter.ToUInt16(mBytes, (int)mTransPos);
        mTransPos = mTransPos + sizeof(ushort);
        return true;
    }
    public bool PopValue(ref float vValue)
    {
        if (mTransPos + sizeof(float) > GetLength())
            return false;

        vValue = System.BitConverter.ToSingle(mBytes, (int)mTransPos);
        mTransPos = mTransPos + sizeof(float);
        return true;
    }
    public bool PopValue(ref double vValue)
    {
        if (mTransPos + sizeof(double) > GetLength())
            return false;

        vValue = System.BitConverter.ToDouble(mBytes, (int)mTransPos);
        mTransPos = mTransPos + sizeof(double);
        return true;
    }
	public bool PopValue(ref long vValue)
	{
		if (mTransPos + sizeof(long) > GetLength())
			return false;
			
		vValue = System.BitConverter.ToInt64(mBytes, (int)mTransPos);
		mTransPos = mTransPos + sizeof(long);
		return true;
	}
	public bool PopValue(ref bool vValue)
	{
		if (mTransPos + sizeof(bool) > GetLength())
            return false;

        vValue = System.BitConverter.ToBoolean(mBytes, (int)mTransPos);
        mTransPos = mTransPos + sizeof(bool);
        return true;
    }
    // 16bit length string
    public bool PopValue(ref string vValue)
    {
        ushort len = 0;
        if (PopValue(ref len) == false)
            return false;

        if (mTransPos + len > GetLength())
            return false;

        vValue = Encoding.UTF8.GetString(mBytes, (int)mTransPos, (int)len);
        mTransPos = mTransPos + len;
        return true;
    }
    // 32bit length string
    public bool PopValueEx(ref string vValue)
    {
        uint len = 0;
        if (PopValue(ref len) == false)
            return false;

        if (mTransPos + len > GetLength())
            return false;

        vValue = Encoding.UTF8.GetString(mBytes, (int)mTransPos, (int)len);
        mTransPos = mTransPos + len;
        return true;
    }
	// 把剩下的数据作为buffer
	public bool PopOctetsToEnd( ByteArray octets )
	{
		uint tLength = GetLength( ) - mTransPos;
		if (tLength == 0)
			return true;

		if (mTransPos + tLength > GetLength())
			return false;
			
		if (octets.mPos + tLength > octets.mSize)
		{
			octets.mSize = Math.Max(octets.mSize + (uint)tLength, octets.mSize + octets.mSize);
			if ( octets.mSize > 65535 )
                Debug.Log( "内存分配过大 - " + octets.mSize );
				
			System.Array.Resize<byte>(ref octets.mBytes, (int)octets.mSize);
		}
			
		//			MemoryStream tStream = new MemoryStream( GetBytes( ), (int) mTransPos, (int) tLength );
		sTempStream.Position = 0;
		sTempStream.Write(GetBytes(), (int)mTransPos, (int)tLength);
		sTempStream.Position = 0;
		sTempStream.Read(octets.GetBytes(), (int)octets.mPos, (int)tLength);
		octets.mPos = octets.mPos + tLength;
		mTransPos = mTransPos + tLength;
		return true;
	}
	// 读取指定字节长度的Buffer
	public bool PopValue(ByteArray octets, int lenSize )
	{
		byte[] ph = new byte[4];
		for ( int i = 0; i < lenSize; i ++ )
		{
			if ( PopValue( ref ph[i] ) == false )
				return false;
		}

		uint tLength = BitConverter.ToUInt32( ph, 0 );
		if (tLength == 0)
			return true;
			
		if (mTransPos + tLength > GetLength())
			return false;
			
		if (octets.mPos + tLength > octets.mSize)
		{
			octets.mSize = Math.Max(octets.mSize + (uint)tLength, octets.mSize + octets.mSize);
			if ( octets.mSize > 65535 )
                Debug.Log( "内存分配过大 - " + octets.mSize );
				
			System.Array.Resize<byte>(ref octets.mBytes, (int)octets.mSize);
		}
			
		//			MemoryStream tStream = new MemoryStream( GetBytes( ), (int) mTransPos, (int) tLength );
		sTempStream.Position = 0;
		sTempStream.Write(GetBytes(), (int)mTransPos, (int)tLength);
		sTempStream.Position = 0;
		sTempStream.Read(octets.GetBytes(), (int)octets.mPos, (int)tLength);
		octets.mPos = octets.mPos + tLength;
		mTransPos = mTransPos + tLength;
		return true;
	}
	// 默认读取四字节为长度的buffer
	public bool PopValue(ByteArray octets)
	{
		uint tLength = 0;
		if (PopValue(ref tLength) == false)
			return false;
			
		if (tLength == 0)
			return true;

        if (mTransPos + tLength > GetLength())
            return false;

        if (octets.mPos + tLength > octets.mSize)
        {
            octets.mSize = Math.Max(octets.mSize + (uint)tLength, octets.mSize + octets.mSize);
			if ( octets.mSize > 65535 )
                Debug.Log( "内存分配过大 - " + octets.mSize );

			System.Array.Resize<byte>(ref octets.mBytes, (int)octets.mSize);
        }

        //			MemoryStream tStream = new MemoryStream( GetBytes( ), (int) mTransPos, (int) tLength );
        sTempStream.Position = 0;
        sTempStream.Write(GetBytes(), (int)mTransPos, (int)tLength);
        sTempStream.Position = 0;
        sTempStream.Read(octets.GetBytes(), (int)octets.mPos, (int)tLength);
        octets.mPos = octets.mPos + tLength;
        mTransPos = mTransPos + tLength;
        return true;
    }
    // raw 函数
    public void Insert(ByteArray vBuffer, uint vStartIndex, uint vCount)
    {
        if (vStartIndex > vBuffer.GetLength())
            return;

        if (vStartIndex + vCount > vBuffer.GetLength())
            return;

        if (mPos + vCount > mSize)
        {
            mSize = Math.Max(mSize + vBuffer.GetLength(), mSize + mSize);
			if ( mSize > 65535 )
                Debug.Log( "内存分配过大 - " + mSize );

			System.Array.Resize<byte>(ref mBytes, (int)mSize);
        }

        sTempStream.Position = 0;
        sTempStream.Write(vBuffer.GetBytes(), (int)vStartIndex, (int)vCount);
        sTempStream.Position = 0;
        sTempStream.Read(mBytes, (int)mPos, (int)vCount);
        mPos = mPos + vCount;
    }
    public void Insert(ByteArray vBuffer)
    {
        if (mPos + vBuffer.GetLength() > mSize)
        {
            mSize = Math.Max(mSize + vBuffer.GetLength(), mSize + mSize);
			if ( mSize > 65535 )
                Debug.Log( "内存分配过大 - " + mSize );

			System.Array.Resize<byte>(ref mBytes, (int)mSize);
        }

        sTempStream.Position = 0;
        sTempStream.Write(vBuffer.GetBytes(), 0, (int)vBuffer.GetLength());
        sTempStream.Position = 0;
        sTempStream.Read(mBytes, (int)mPos, (int)vBuffer.GetLength());
        mPos = mPos + vBuffer.GetLength();
    }
    public void Erase(uint startIndex, uint count)
    {
        if (startIndex > GetLength())
            return;

        if (startIndex + count > GetLength())
            return;

        sTempStream.Position = 0;
        sTempStream.Write(mBytes, (int)(startIndex + count), (int)(GetLength() - (startIndex + count)));
        sTempStream.Position = 0;
        sTempStream.Read(mBytes, 0, (int)(GetLength() - (startIndex + count)));
        mPos = (uint)(GetLength() - (startIndex + count));
    }
    public void Clear()
    {
        mRecordPos = 0;
        mTransPos = 0;
        mPos = 0;
    }
}
